﻿#include "aport.h"
#include "thread"
using namespace XIOPlug;
using namespace asio;
APort::APort(QObject* parent)
{
	Dev dev;
	dev.port = "COM1";
	dev.baud = "9600";
	dev.dataBits = "8";
	dev.stopBits = "1";
	dev.parity = "0";
	dev.flowControl = "0";
	setDev(dev);
}
bool APort::openDev(XIOPlug::Dev& dev)
{
	setDev(dev);
//	asio::io_service io_s;
	if (_handle.isNull()) {
		try {
			_handle.reset(new serial_port(io_s, "COM2"));// dev.port.toStdString()));
		}
		catch (std::exception& e) {
			qDebug() << "打开失败" << dev.port << QString(e.what());
			setStatus(openFail);
			return false;
		}
	}
	else {
		_handle->open("COM2");// dev.port.toStdString()));
	}
	_handle->set_option(serial_port_base::baud_rate(dev.baud.toInt()));
	_handle->set_option(serial_port_base::flow_control((serial_port_base::flow_control::type)(dev.flowControl.toInt())));
	_handle->set_option(serial_port_base::parity((serial_port_base::parity::type)(dev.parity.toInt())));
	_handle->set_option(serial_port_base::stop_bits((serial_port_base::stop_bits::type)(dev.stopBits.toInt()-1)));
	_handle->set_option(serial_port_base::character_size(dev.dataBits.toInt()));
	setStatus(opened);
	_readSlot();
	if (_timer.isNull()) {
		_timer.reset(new QTimer());
		connect(_timer.get(), &QTimer::timeout, this, &APort::_runAPP);
		_timer->start(1);
	}
	//io_s.stop();
	t.reset( new std::thread([&]() {
		io_s.run();
		}));
	return true;
}
void APort::colseDev()
{

}


//void handle_write(const error_code& error, size_t bytes_transferred)
//{
//	if (!error) {
//		//std::cout << "Async wrote " << bytes_transferred << " bytes." << std::endl;
//	}
//	else {
//		//std::cerr << "Write failed: " << error.message() << std::endl;
//	}
//}
void APort::_runAPP()
{
	static char buffer[1024*1024];
	int count = 0;
	if (getStatus() == opened) {
		_Tmutex.lock();
		QList<IOStream> sended;
		QList<IOStream> erred;
		uint tdatasize = 0, edatasize = 0;
		QQueue<IOStream> _t(*_Tdata);
		_Tdata->clear();
		_Tmutex.unlock();
		
		while (_t.size())
		{

			auto d = _t.dequeue();
			sended.append(d);
			setTnum(getTnum() + 1);
			setTdataSize(getTdataSize() + d.data.size());
			memcpy(buffer+count, d.data.data(), d.data.size());
			count += d.data.size();
			t_count += d.data.size();
		}
		if(count)
		_handle->async_write_some(asio::buffer(buffer, count), std::bind(&APort::handle_write, this,
			std::placeholders::_1, std::placeholders::_2));
		if (!sended.isEmpty())
		{
			emit sendIOStreamed(sended);
		}
		if (!erred.isEmpty())
		{
			setEdataSize(getEdataSize() + edatasize);
			setEnum(getEnum() + erred.size());
			emit sendError(erred);
		}

	}

}

void APort::_readSlot()
{
	_handle->async_read_some(asio::buffer(_buffer),
		std::bind(&APort::handle_read, this,
			std::placeholders::_1, std::placeholders::_2));
}

void APort::handle_read(const asio::error_code& error, size_t bytes_transferred) {
	if (!error) {
		_Rmutex.lock();
		QByteArray d(_buffer, bytes_transferred);
		setRnum(getRnum() + 1);
		setRdataSize(getRdataSize() + bytes_transferred);
		_Rdata->enqueue(IOStream{ QTime::currentTime(),getPort(),d});
		_Rmutex.unlock();
		emit readReady();
		// 继续等待更多数据
		this->_readSlot();
	}
	else {
		// 处理错误
		qCritical() << "Read failed: " << QString::fromStdString(error.message());
	}
}

#include <iostream>
void APort::handle_write(const error_code& error, size_t bytes_transferred)
{
	if (!error) {
		//std::cout<<"Async wrote " << bytes_transferred << " bytes." <<error.message();
		//qDebug() << "Async wrote " << bytes_transferred << " bytes." << QString::fromStdString(error.message());
	}
	else {
		//std::cerr << "Write failed: " << error.message() <<error.message();
		qDebug() << "Write failed: " << QString::fromStdString(error.message());
	}
}